/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.IO;
using NDODS.DAP.BaseTypes;
using NDODS.DAP.Exceptions;

namespace NDODS.DAP.Primitives
{
    /// <summary> A vector of booleans.
    /// 
    /// </summary>
    /// <author>  ndp
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="PrimitiveVector">
    /// </seealso>
    [Serializable]
    public class BooleanPrimitiveVector : PrimitiveVector, ICloneable
    {
        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Returns the number of elements in the array.
        /// 
        /// </summary>
        /// <returns> the number of elements in the array.
        /// </returns>
        /// <summary> Sets the number of elements in the array.  Allocates a new primitive
        /// array of the desired size.  Note that if this is called multiple times,
        /// the old array and its contents will be lost.
        /// <p/>
        /// Only called inside of <code>Deserialize</code> method or in derived
        /// classes on server.
        /// 
        /// </summary>
        /// <param name="len">the number of elements in the array.
        /// </param>
        public override int Length
        {
            get { return vals.Length; }

            set { vals = new bool[value]; }
        }

        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Returns (a reference to) the internal storage for this PrimitiveVector
        /// object.
        /// <h2>WARNING:</h2>
        /// Because this method breaks encapsulation rules the user must beware!
        /// If we (the OPeNDAP prgramming team) choose to change the internal
        /// representation(s) of these types your code will probably break.
        /// <p/>
        /// This method is provided as an optimization to eliminate massive
        /// copying of data.
        /// 
        /// </summary>
        /// <returns> The internal array of bool values.
        /// </returns>
        /// <summary> Set the internal storage for PrimitiveVector.
        /// <h2><i>WARNING:</i></h2>
        /// Because this method breaks encapsulation rules the user must beware!
        /// If we (the OPeNDAP prgramming team) choose to change the internal
        /// representation(s) of these types your code will probably break.
        /// <p/>
        /// This method is provided as an optimization to eliminate massive
        /// copying of data.
        /// </summary>
        public override Object InternalStorage
        {
            get { return (vals); }

            set { vals = (bool[]) value; }
        }

        /// <summary> the array of <code>float</code> values.</summary>
        private bool[] vals;

        /// <summary> Constructs a new <code>BooleanPrimitiveVector</code>.
        /// 
        /// </summary>
        /// <param name="var">the template <code>BaseType</code> to use.
        /// </param>
        public BooleanPrimitiveVector(BaseType var) : base(var)
        {
        }

        /// <summary> Returns a clone of this <code>BooleanPrimitiveVector</code>.  A deep
        /// copy is performed on all data inside the variable.
        /// 
        /// </summary>
        /// <returns> a clone of this <code>BooleanPrimitiveVector</code>.
        /// </returns>
        public override Object Clone()
        {
            BooleanPrimitiveVector v = (BooleanPrimitiveVector) base.Clone();
            if (vals != null)
            {
                v.vals = new bool[vals.Length];
                Array.Copy(vals, 0, v.vals, 0, vals.Length);
            }
            return v;
        }

        /// <summary> Return the i'th value as a <code>double</code>.
        /// 
        /// </summary>
        /// <param name="i">the index of the value to return.
        /// </param>
        /// <returns> the i'th value.
        /// </returns>
        public bool getValue(int i)
        {
            return vals[i];
        }

        /// <summary> Set the i'th value of the array.
        /// 
        /// </summary>
        /// <param name="i">     the index of the value to set.
        /// </param>
        /// <param name="newVal">the new value.
        /// </param>
        public void setValue(int i, bool newVal)
        {
            vals[i] = newVal;
        }

        /// <summary> Prints the value of all variables in this vector.  This
        /// method is primarily intended for debugging OPeNDAP applications and
        /// text-based clients such as geturl.
        /// 
        /// </summary>
        /// <param name="os">   the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="space">this value is passed to the <code>PrintDeclaration</code> method,
        /// and controls the leading spaces of the output.
        /// </param>
        /// <seealso cref="BaseType.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        public override void printVal(StreamWriter os, String space)
        {
            int len = vals.Length;
            for (int i = 0; i < len - 1; i++)
            {
                os.Write(vals[i]);
                os.Write(", ");
            }
            // Print last value, if any, without trailing comma
            if (len > 0)
                os.Write(vals[len - 1]);
        }

        /// <summary> Prints the value of a single variable in this vector.
        /// method is used by <code>DArray</code>'s <code>PrintValue</code> method.
        /// 
        /// </summary>
        /// <param name="os">   the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="index">the index of the variable to Print.
        /// </param>
        /// <seealso cref="DArray.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        public override void printSingleVal(StreamWriter os, int index)
        {
            os.Write(vals[index]);
        }

        /// <summary> Reads data from a <code>DataInputStream</code>. This method is only used
        /// on the client side of the OPeNDAP client/server connection.
        /// 
        /// </summary>
        /// <param name="source">  a <code>DataInputStream</code> to Read from.
        /// </param>
        /// <param name="sv">      The <code>ServerVersion</code> returned by the server.
        /// (used by <code>DSequence</code> to determine which protocol version was
        /// used).
        /// </param>
        /// <param name="statusUI">The <code>StatusUI</code> object to use for GUI updates
        /// and user cancellation notification (may be null).
        /// </param>
        /// <throws>  DataReadException when invalid data is Read, or if the user </throws>
        /// <summary>                           cancels the download.
        /// </summary>
        /// <throws>  EOFException      if EOF is found before the variable is completely </throws>
        /// <summary>                           deserialized.
        /// </summary>
        /// <throws>  IOException       thrown on any other InputStream exception. </throws>
        /// <seealso cref="ClientIO.deserialize(DataInputStream, ServerVersion, StatusUI)">
        /// </seealso>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        //UPGRADE_NOTE: Synchronized keyword was removed from method 'Deserialize'. Lock expression was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1027'"
        public override void Deserialize(BinaryReader source, ServerVersion sv, IStatusUI statusUI)
        {
            lock (this)
            {
                for (int i = 0; i < vals.Length; i++)
                {
                    vals[i] = source.ReadBoolean();
                    if (statusUI != null)
                    {
                        statusUI.IncrementByteCount(1);
                        if (statusUI.UserCancelled())
                            throw new DataReadException("User cancelled");
                    }
                }
            }
        }

        /// <summary> Writes data to a <code>DataOutputStream</code>. This method is used
        /// on the server side of the OPeNDAP client/server connection, and possibly
        /// by GUI clients which need to download OPeNDAP data, manipulate it, and
        /// then resave it as a binary file.
        /// 
        /// </summary>
        /// <param name="sink">a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> exception. </throws>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public override void Externalize(BinaryWriter sink)
        {
            for (int i = 0; i < vals.Length; i++)
            {
                sink.Write(vals[i]);
            }
        }

        /// <summary> Write a subset of the data to a <code>DataOutputStream</code>.
        /// 
        /// </summary>
        /// <param name="sink">   a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <param name="start"> starting index (i=start)
        /// </param>
        /// <param name="stop">  ending index (i<=stop)
        /// </param>
        /// <param name="stride">index stride (i+=stride)
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> exception. </throws>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public virtual void externalize(BinaryWriter sink, int start, int stop, int stride)
        {
            for (int i = start; i <= stop; i += stride)
                sink.Write(vals[i]);
        }

        /// <summary> Create a new primitive vector using a subset of the data.
        /// 
        /// </summary>
        /// <param name="start"> starting index (i=start)
        /// </param>
        /// <param name="stop"> ending index (i<=stop)
        /// </param>
        /// <param name="stride">index stride (i+=stride)
        /// </param>
        /// <returns> new primitive vector, of type BooleanPrimitiveVector.
        /// </returns>
        public override PrimitiveVector subset(int start, int stop, int stride)
        {
            BooleanPrimitiveVector n = new BooleanPrimitiveVector(Template);
            stride = Math.Max(stride, 1);
            stop = Math.Max(start, stop);
            int length = 1 + (stop - start)/stride;
            n.Length = length;

            int count = 0;
            for (int i = start; i <= stop; i += stride)
            {
                n.setValue(count, vals[i]);
                count++;
            }
            return n;
        }
    }
}